package com.mischa.doedeljas.server;

import java.net.Socket;
import java.util.Vector;

import com.mischa.doedeljas.Card;
import com.mischa.doedeljas.Messages;
import com.mischa.doedeljas.Card.Suit;
import com.mischa.network.SocketIO;

public class Player extends SocketIO
{
	private DoedeljasServer _server;
	private Game _game;
	private int _playerId;
	private Vector<Card> _hand;

	public Player(Socket _socket, DoedeljasServer server) 
	{
		super(_socket);
		_server = server;
	}

	@Override
	public synchronized void messageReceived(int message, int[] arguments) 
	{
		switch(message)
		{
		case Messages.JOIN:
			_server.join(arguments[0], this);
			break;
		case Messages.DUMP:
			dumpCards(arguments);
			break;
		case Messages.TRUMP:
			chooseTrump(Suit.fromInteger(arguments[0]));
			break;
		case Messages.PLAY:
			_game.playCard(new Card(arguments[0]), this);
			break;
		}
	}

	private void chooseTrump(Suit suit) {
		if (_game.getDealer() == _playerId)
		{
			_game.setTrump(suit);
		}
	}

	private void dumpCards(int[] arguments) {
		if (_game.getDealer() == _playerId && _hand.size() == 12 && arguments.length == 2)
		{
			for (int card : arguments)
			{
				_hand.remove(new Card(card));
			}
			
			deal(_hand);
		}
	}

	public int getPlayerId()
	{
		return _playerId;
	}
	
	public boolean holdsCard(Card card)
	{
		return _hand.contains(card);
	}
	
	public void joined(Game game, int playerId) {
		_game = game;
		_playerId = playerId;
		sendMessage(Messages.JOINED, new int[] { game.getGameId(), playerId + 1 });
	}

	public void deal(Vector<Card> hand) {		
		int[] cards = new int[hand.size()];
	
		for (int i = 0; i < cards.length; ++i)
		{
			cards[i] = hand.get(i).toInteger();
		}
		
		sendMessage(Messages.DEALT, cards);
		
		_hand = new Vector<Card>();
		_hand.addAll(hand);
	}

	public void youAreDealer() 
	{
		sendMessage(Messages.YOU_DEAL);
	}
	
	public void trickStatus(Trick trick)
	{
		int[] arguments = new int[4];
		arguments[0] = relativePositionOf(trick.getNextPlayer());
		arguments[1] = getCardForRelativePlayerPosition(trick, 1);
		arguments[2] = getCardForRelativePlayerPosition(trick, 2);
		arguments[3] = getCardForRelativePlayerPosition(trick, 3);
		
		sendMessage(Messages.TRICK, arguments);
	}

	private int getCardForRelativePlayerPosition(Trick trick, int position)
	{
		int index = (_playerId + (position - 1)) % 3;
		Card card = trick.getCard(index);
		return card == null ? Messages.NONE : card.toInteger();
	}
	
	private int relativePositionOf(int playerId) 
	{
		for (int relative = 0; relative < 3; ++relative)
		{		
			if (playerId == (_playerId + relative) % 3)
			{
				return relative + 1;
			}
		}
		
		throw new IllegalArgumentException("Cannot find relative position of player " + playerId);
	}

	public void trumpChosen(Suit suit) {
		sendMessage(Messages.TRUMP, suit.toInteger());
	}
}